#pragma once

#include <iostream>
#include <string>
#include <memory>
// 结构数据的序列化和反序列化
// 解决数据包的粘包问题
namespace Protocal
{

    const std::string Prosep = " ";
    const std::string Blanksep = "\n";
    std::string Encode(const std::string &message)
    {
        std::string len = std::to_string(message.size());
        std::string package = len + Blanksep + message + Blanksep;
        return package;
    }

    bool Decode(std::string &package,std::string *message)
    {
        //除了解包，还要判断报文的完整性
        auto pos = package.find(Blanksep);
        if(pos == std::string::npos) return false;
        std::string lens = package.substr(0,pos);
        int messagelen = std::stoi(lens);
        int total = lens.size() + messagelen + 2 * Blanksep.size();
        if(package.size() < total) return false;
        //至少有一个完整的报文
        *message = package.substr(pos+Blanksep.size(),messagelen);
        package.erase(0,total);
        return true;
    }


    class Request
    {
    public:
        Request()
        {
        }
        Request(int x, int y, char oper) : _data_x(x), _data_y(y), _oper(oper)
        {
        }
        void debug()
        {
            std::cout << "_data_x :" << _data_x << std::endl;
            std::cout << "_data_y :" << _data_y << std::endl;
            std::cout << "_oper :" << _oper << std::endl;
        }
        // 将结构数据转换为字符串
        bool Serialize(std::string *out)
        {
            *out = std::to_string(_data_x) + Prosep + _oper + std::to_string(_data_y);
            return true;
        }
        bool deSerialize(std::string &in)
        {
            auto left = in.find(Prosep);
            if (left == std::string::npos)
                return false;
            auto right = in.rfind(Prosep);
            if (right == std::string::npos)
                return false;
            _data_x = std::stoi(in.substr(0, left));
            _data_y = std::stoi(in.substr(right + 1, std::string::npos));
            std::string oper = in.substr(left + Prosep.size(), right - (left + Prosep.size()));
            if (oper.size() != 1)
                return false;
            _oper = oper[0];
            return true;
        }
        int Getdata_x()
        {
            return _data_x;
        }
        int Getdata_y()
        {
            return _data_y;
        }
        char Get_oper()
        {
            return _oper;
        }
    private:
        // 解析为 "len\nx op y\n"
        int _data_x; // 参数1
        int _data_y; // 参数2
        char _oper;  //+-*/
    };

    class Reponse
    {
    public:
        Reponse()
        {
        }
        Reponse(int result, int code = 0) : _result(result), _code(code)
        {
        }
        bool Serialize(std::string *out)
        {
            *out = std::to_string(_result) + Prosep + std::to_string(_code);
            return true;
        }
        bool deSerialize(std::string &in)
        {
            auto pos = in.find(Prosep);
            if (pos == std::string::npos)
                return false;
            _result = std::stoi(in.substr(0, pos));
            _code = std::stoi(in.substr(pos + 1));
            return true;
        }
        void Setresult(int res)
        {
             _result = res;
        }
        void SetCode(int code)
        {
            _code = code;
        }
        int GetResult ()
        {
            return _result; 
        }
    private:
        // 解析为 "len\n_result _code\n"
        int _result;
        int _code;
    };

    class Factory
    {
    public:
        std::shared_ptr<Request> BuildRequest()
        {
            std::shared_ptr<Request> rep = std::make_shared<Request>();
            return rep;
        }
        std::shared_ptr<Request> BuildRequest(int x, int y, char op)
        {
            std::shared_ptr<Request> rep = std::make_shared<Request>(x, y, op);
            return rep;
        }
        std::shared_ptr<Reponse> BuildRespose()
        {
            std::shared_ptr<Reponse> rep = std::make_shared<Reponse>();
            return rep;
        }

        std::shared_ptr<Reponse> BuildRespose(int x, int y)
        {
            std::shared_ptr<Reponse> rep = std::make_shared<Reponse>(x, y);
            return rep;
        }
    };
}